package com.htd.htdapmservice.service.impl;

import com.acooly.core.utils.Ids;
import com.alibaba.fastjson.JSON;
import com.htd.htdapmapi.alarm.request.AlarmInto;
import com.htd.htdapmapi.alarm.result.AlarmResult;
import com.htd.htdapmapi.common.CommonResult;
import com.htd.htdapmcommon.constants.AlarmConstants;
import com.htd.htdapmcommon.constants.ErrorCodeConstants;
import com.htd.htdapmcommon.enums.*;
import com.htd.htdapmcommon.util.DateUtil;
import com.htd.htdapmcommon.util.HttpUtils;
import com.htd.htdapmcommon.util.RedisUtil;
import com.htd.htdapmcommon.util.StringUtil;
import com.htd.htdapmdmo.AlarmsInfo;
import com.htd.htdapmdmo.OneAlertAlarmsRecordInfo;
import com.htd.htdapmdmo.OneAlertKey;
import com.htd.htdapmservice.dao.AlarmsInfoDao;
import com.htd.htdapmservice.dao.OneAlertAlarmsRecordDao;
import com.htd.htdapmservice.request.SearchAlarmInto;
import com.htd.htdapmservice.result.*;
import com.htd.htdapmservice.service.intf.AlarmsInfoService;
import com.htd.htdapmservice.service.intf.OneAlertKeyService;
import com.htd.htdapmservice.service.intf.OneAlertService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.text.ParseException;
import java.util.*;

import javax.annotation.Resource;

/**
 *
 * Service层（实现类）
 *
 */
@Component
@Service
public class OneAlertServiceImpl implements OneAlertService {

	private static final Logger LOGGER = LoggerFactory.getLogger(OneAlertServiceImpl.class);

	@Autowired
	private JavaMailSenderImpl mailSender;

	/**
	 *  调用接口--获取认证的地址
	 */
	@Value("${app.getAuthenticationPath}")
	private String getAuthenticationPath;

	/**
	 * 调用接口--查询我的告警的地址
	 */
	@Value("${app.getSearchAlarmPath}")
	private String getSearchAlarmPath;

	@Value("${app.user}")
	private String user;

	@Value("${app.password}")
	private String password;

	@Value("${spring.mail.properties.from}")
	private String from;

	@Value("${spring.mail.properties.to}")
	private String to;

	@Autowired
	private RedisUtil redisUtil;

	@Autowired
	private AlarmsInfoDao alarmsInfoDao;

	@Autowired
	private OneAlertAlarmsRecordDao oneAlertAlarmsRecordDao;

	@Autowired
	private AlarmsInfoService alarmsInfoService;
	@Autowired
	private OneAlertKeyService oneAlertKeyService;
	@Resource
	private TransportClient client;

	@Autowired
	private AmqpTemplate rabbitTemplate;


	/**
	 * 调用接口--获取认证
	 */
	@Override
	public CommonResult getAuthentication() {
		CommonResult  commonResult =null;
		try {
			HashMap<String, String> params = new HashMap<String, String>();
			params.put("user",user);
			params.put("password",password);
			String result = HttpUtils.sendPostMessage(params, AlarmConstants.ENCODE_UTF, getAuthenticationPath);
			AuthenticationResult authenticationResult=JSON.parseObject(result, AuthenticationResult.class);
			commonResult =new CommonResult();
			if(AlarmConstants.ALARMA_SUCCESS.equals(authenticationResult.getCode())){
				redisUtil.set(AlarmConstants.ONE_ALERT_TOKEN,authenticationResult.getData().getToken(),AlarmConstants.ONE_ALERT_TOKEN_EXPIRE);
			}else{
				commonResult.fail(authenticationResult.getCode(),authenticationResult.getMessage());
			}
			return commonResult;
		}catch (Exception e){
			LOGGER.error("调用第三方获取token接口异常",e);
			commonResult =new CommonResult();
			commonResult.fail(ErrorCodeConstants.SYSTEM_ERROR_CODE,ErrorCodeConstants.SYSTEM_ERROR_MSG);
			return commonResult;
		}
	}



	/**
	 * 调用接口--创建告警API
	 */
	@Async("taskExecutor")
	@Override
	public AlarmResult createAlarm(AlarmInto alarmInto) {
		AlarmResult alarmResult = null;
		//参数校验
		try{
			if(!checkCreateAlarm(alarmInto)){
				alarmResult =new AlarmResult();
				alarmResult.setResponseMsg(ErrorCodeConstants.ERROR_PARAM_MSG);
				alarmResult.setResponseCode(ErrorCodeConstants.ERROR_PARAM_CODE);
				return alarmResult;
			}
			//邮件告警推送
			CreateAlarmResult createAlarmResult  =sendAlarmInfo(alarmInto);
			alarmResult =new AlarmResult();
			if(createAlarmResult !=null && AlarmConstants.ALARMA_SUCCESS.equals(createAlarmResult.getCode())){
				Map<String,Object> map = new HashMap<String,Object>();
				map.put("sendStatus",AlarmSendStatus.SEND_YES);
				map.put("alarmsId",alarmInto.getAlarmsId());
				map.put("updateTime",new Date());
				LOGGER.info("创建告警成功后更新状态map:{}",map);
				alarmsInfoService.updateSendStatusByAlarmsId(map);
			}
			return alarmResult;
		}catch (Exception e){
			LOGGER.error("调用第三方告警接口异常",e);
			alarmResult =new AlarmResult();
			alarmResult.setResponseMsg(ErrorCodeConstants.SYSTEM_ERROR_MSG);
			alarmResult.setResponseCode(ErrorCodeConstants.SYSTEM_ERROR_CODE);
			return alarmResult;
		}
	}
	/**
	 * 保存调用创建告警API时输入的参数到数据库
	 *
	 */
	public void saveAlarmInto(AlarmInto alarmInto) {
		LOGGER.info("创建告警时的入参保存到数据库alarmInto:{}",alarmInto);
		alarmsInfoDao.saveAlarmInto(buildAlarmInfo(alarmInto));
	}

	/**
	 * 发送告警服务到告警邮箱
	 * @param alarmInto
	 * @return
	 */
	public CreateAlarmResult sendAlarmInfo(AlarmInto alarmInto){
		CreateAlarmResult createAlarmResult = new CreateAlarmResult();
		try {
			SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
			//发送邮箱
			simpleMailMessage.setFrom(from);
			//接受邮箱
			simpleMailMessage.setTo(to);
			//抄送邮箱
			//simpleMailMessage.copyTo(xxx);
			//告警标题
			simpleMailMessage.setSubject(StringUtils.isNotBlank(alarmInto.getAlarmsTitle()) ? alarmInto.getAlarmsTitle() : "告警邮件");
			//告警信息
			String format = "有新告警！ \r\n" +
					"\r\n" +
					"告警标题：{0}\r\n" +
					"\r\n" +
					"告警编号：{1}\r\n" +
					"\r\n" +
					"告警时间：{2}\r\n" +
					"\r\n" +
					"告警级别：{3}\r\n" +
					"\r\n" +
					"告警应用：{4}\r\n" +
					"\r\n" +
					"告警内容：{5}\r\n" +
					"\r\n" +
					"主机：{6}";
			String alarmName = alarmInto.getAlarmsTitle();
			String eventId ="";
			if(StringUtils.isEmpty(alarmInto.getAlarmsId())){
				eventId =Ids.getDid();
			}else{
				eventId = alarmInto.getAlarmsId();
			}
			String priority = alarmInto.getPriority();
			String app = "";
		    if(StringUtils.isNotEmpty(alarmInto.getApp())){
			    app = alarmInto.getApp();
		    }else{
			    if (!redisUtil.exists(AlarmConstants.getOneAlertKey(alarmInto.getProductType()))){
				    OneAlertKey oneAlertKey = oneAlertKeyService.findOneAlertKeyByProductCode(alarmInto.getProductType());
				    redisUtil.set(AlarmConstants.getOneAlertKey(alarmInto.getProductType()),oneAlertKey.getProductKeyt(),AlarmConstants.ONE_ALERT_TOKEN_EXPIRE);
	                app = oneAlertKey.getProductKeyt();
			    }else{
	                app = redisUtil.get(AlarmConstants.getOneAlertKey(alarmInto.getProductType()));
	            }
		    }
		    String alarmContent = alarmInto.getAlarmsDetail();
			String host = alarmInto.getHost();
			String text = MessageFormat.format(format, alarmName, eventId, new Date(), priority, app, alarmContent, host);
			simpleMailMessage.setText(text);
			mailSender.send(simpleMailMessage);
			LOGGER.info("发送邮件成功：{}->{}", from, to);
		} catch (Exception e) {
			createAlarmResult.setMessage(ErrorCodeConstants.SYSTEM_ERROR_MSG);
			createAlarmResult.setCode(ErrorCodeConstants.SYSTEM_ERROR_CODE);
			return createAlarmResult;
		}
		createAlarmResult.setMessage(ErrorCodeConstants.SUCCESS_MSG);
		createAlarmResult.setCode(AlarmConstants.ALARMA_SUCCESS);
		return createAlarmResult;
	}


	/**
	 * 校验创建告警接口参数
	 * @param alarmInto
	 * @return true/false
	 */
	private boolean checkCreateAlarm(AlarmInto alarmInto){
		if(StringUtil.isAnyNullOrEmpty(alarmInto.getAlarmsTitle(),alarmInto.getAlarmsDetail(),alarmInto.getEventType(),alarmInto.getProductType())){
			LOGGER.info("参数校验不通过");
			return false;
		}
		return true;
	}

	/**
	 * 调用接口--查询我的告警
	 * 功能：获取告警信息，放入表“one_alert_alarms_record”，
	 *       采用没有则insert，有则update
	 */
	@Override
	public SearchAlarmResult searchAlarm(SearchAlarmInto searchAlarmInto) {
		// 1、接口权限验证
		if(StringUtils.isBlank(redisUtil.get(AlarmConstants.ONE_ALERT_TOKEN))){
			CommonResult commonResult  =getAuthentication();
			if(!ErrorCodeConstants.SUCCESS_CODE.equals(commonResult.getResponseCode())){
				LOGGER.error("获取onealert token失败{}",commonResult);
				return null;
			}
		}
		// 2、查询指定状态（ACK,CLOSED）告警
		HashMap<String, String> params = new HashMap<String, String>();
		if (StringUtils.isNotBlank(searchAlarmInto.getStatus())) {
			params.put("status", searchAlarmInto.getStatus());
		}
		params.put("time" , "today");
		params.put("UPYOO_TOKEN", redisUtil.get(AlarmConstants.ONE_ALERT_TOKEN));
		String result = HttpUtils.sendGetMessage(params, AlarmConstants.ENCODE_UTF, getSearchAlarmPath);
		//LOGGER.info("查询第三方告警记录{}",result);
		SearchAlarmResult searchAlarmResult =JSON.parseObject(result,SearchAlarmResult.class);
		if(null== searchAlarmResult){
			LOGGER.error("查询告警记录返回为空");
			return null;
		}
		// 3、更新状态
		if(AlarmConstants.SEARCH_ALARMA_SUCCESS.equals(searchAlarmResult.getCode())){
			 List<AlarmsInfo> updateAlarmsList =new ArrayList<AlarmsInfo>();
			 List<AlarmsInfo> alarmsInfoList =alarmsInfoDao.getAlarmsInfoListByAlarmStatus();
			 //因为ES不方便批量更新，故单条更新，否则应采用批量更新
			 if(CollectionUtils.isNotEmpty(alarmsInfoList)){
				 for(AlarmsInfo info:alarmsInfoList){
					for(SearchAlarmDataResult searchAlarmDataResult:searchAlarmResult.getData()){
						if(searchAlarmDataResult.getEntityId().equals(info.getAlarmsId())){
							//1.更新ES
							if(!updateAlarm(searchAlarmDataResult.getEntityId(),searchAlarmDataResult.getStatus(),info.getAlarmsProductTypeCode())){ //String alarmId, String alarmStatus
								break; //如果更新ES失败，则，跳出循环
							}
							//2.预留批量更新
							info.setAlarmsStatus(AlarmsStatusEnum.valueOf(searchAlarmDataResult.getStatus()));
							LOGGER.info("待更新告警信息alarmID:{},状态:{}",searchAlarmDataResult.getEntityId(),searchAlarmDataResult.getStatus());
							updateAlarmsList.add(info);
						}
					}
				 }
			 }
			 if(CollectionUtils.isNotEmpty(updateAlarmsList)){
				 alarmsInfoDao.batchUpdate(updateAlarmsList);
			 }
		}
		return searchAlarmResult;
	}

	/**
	 * 将查询告警结果保存到数据库到数据库
	 * @throws ParseException
	 *
	 */
	public void saveSearchAlarmInto(SearchAlarmResult searchAlarmResult) throws ParseException {

		if(CollectionUtils.isEmpty(searchAlarmResult.getData())){
			return ;
		}
		List<String> alarmsList= oneAlertAlarmsRecordDao.getAllAlarmId();
		OneAlertAlarmsRecordInfo oneAlertAlarmsRecordInfo= null;
		List<OneAlertAlarmsRecordInfo> alarmsRecordInfoList =new ArrayList<OneAlertAlarmsRecordInfo>();
		List<OneAlertAlarmsRecordInfo> updateAlarmsList =new ArrayList<OneAlertAlarmsRecordInfo>();
		BeanCopier copier =null;
		for(SearchAlarmDataResult searchAlarmDataResult:searchAlarmResult.getData()){
			oneAlertAlarmsRecordInfo=new OneAlertAlarmsRecordInfo();
			copier = BeanCopier.create(SearchAlarmDataResult.class, OneAlertAlarmsRecordInfo.class, false);
			copier.copy(searchAlarmDataResult,oneAlertAlarmsRecordInfo, null);
			oneAlertAlarmsRecordInfo.setCreateTime(DateUtil.getSqlDateTimeByStr2(DateUtil.getStrDate(new Date())));
			oneAlertAlarmsRecordInfo.setPriority(Integer.parseInt(searchAlarmDataResult.getPriority()));
			oneAlertAlarmsRecordInfo.setUpdateTime(DateUtil.getDateOfTimeStr(DateUtil.formatDateWithTime(new Date())));
			oneAlertAlarmsRecordInfo.setCloseTime("");
			if(StringUtils.isNotEmpty(oneAlertAlarmsRecordInfo.getService()) && oneAlertAlarmsRecordInfo.getService().length() >20){
				oneAlertAlarmsRecordInfo.setService(oneAlertAlarmsRecordInfo.getService().substring(0,19));
			}
			if(alarmsList.contains(searchAlarmDataResult.getAlarmId())){
				updateAlarmsList.add(oneAlertAlarmsRecordInfo);
			}else{
				alarmsRecordInfoList.add(oneAlertAlarmsRecordInfo);
			}
		}
		if(CollectionUtils.isNotEmpty(alarmsRecordInfoList)){
			try {
				oneAlertAlarmsRecordDao.batchSave(alarmsRecordInfoList);
			} catch (Exception e) {
				LOGGER.error("向数据库存储数据发生异常",e);
			}
		}
		
		if(CollectionUtils.isNotEmpty(updateAlarmsList)){
		      try {
		        oneAlertAlarmsRecordDao.batchUpdate(updateAlarmsList);
		      } catch (Exception e) {
		        LOGGER.error("向数据库更新数据发生异常",e);
		      }
		    }
	}


	/**
	 * 构造入库对象
	 * @param alarmInto
	 * @return
	 */
	private AlarmsInfo buildAlarmInfo(AlarmInto alarmInto){
		AlarmsInfo alarmsInfo = new AlarmsInfo();
		alarmsInfo.setAlarmsNo(Ids.getDid("gj"));
		alarmsInfo.setAlarmsEventType(alarmInto.getEventType());
		alarmsInfo.setAlarmsId(alarmInto.getAlarmsId());
		alarmsInfo.setAlarmsDetail(alarmInto.getAlarmsDetail());
		if (StringUtils.isNotBlank(alarmInto.getPriority())) {
			alarmsInfo.setAlarmsPriorityCode(Integer.parseInt(alarmInto.getPriority()));
			if(AlarmConstants.TYPE_ZABBIX.equalsIgnoreCase(alarmInto.getProductType())){
				alarmsInfo.setAlarmsPriorityMsg(ZabbixLevelEnum.getValueByCode(alarmInto.getPriority()));
			}else{
				alarmsInfo.setAlarmsPriorityMsg(AlarmsLevelEnum.getValueByCode(alarmInto.getPriority()));
			}
		}
		if (StringUtils.isNotBlank(alarmInto.getAlarmsTitle())) {
			if(alarmInto.getAlarmsDetail().length()>800){
				alarmsInfo.setAlarmsTitle(alarmInto.getAlarmsTitle().substring(0,799));
			}else{
				alarmsInfo.setAlarmsTitle(alarmInto.getAlarmsTitle());
			}
		}
		alarmsInfo.setAlarmsChannel(StringUtils.isBlank(alarmsInfo.getAlarmsChannel())?AlarmsChannelStatus.ONE_ALERT.getCode() :alarmsInfo.getAlarmsChannel());
		alarmsInfo.setAlarmsProductTypeCode(alarmInto.getProductType());
		alarmsInfo.setAlarmsProductTypeMsg(oneAlertKeyService.findOneAlertKeyByProductCode(alarmInto.getProductType()).getProductName());
		return alarmsInfo;
	}
	/**
	 * 批量保存调用创建告警API时输入的参数到数据库
	 *
	 */
	public int batchSaveAlarmInto(List<AlarmInto> alarmIntos) {
		if (CollectionUtils.isEmpty(alarmIntos)) {
			return 0;
		}
		List<AlarmsInfo> alarmsInfos = new ArrayList<>();
		for (AlarmInto alarmInto :alarmIntos ) {
			if(!checkCreateAlarm(alarmInto)){
				continue;
			}
			alarmsInfos.add(buildAlarmInfo(alarmInto));
		}
		int count =alarmsInfoDao.batchSaveAlarmInto(alarmsInfos);
		if(count>0){
			LOGGER.info("批量插入告警信息表成功");
		}else{
			LOGGER.info("批量插入告警信息表失败");
		}
		return count;

	}

	/**
	 * 调用接口--创建告警API
	 */
	@Override
	public AlarmResult batchCreateAlarm(List<AlarmInto> alarmIntos) {
		AlarmResult alarmResult = null;
		//参数校验
		try{
			//将入参保存到数据库
			batchSaveAlarmInto(alarmIntos);
			for (AlarmInto alarmInto:alarmIntos) {
				CreateAlarmResult createAlarmResult  =sendAlarmInfo(alarmInto);
				alarmResult =new AlarmResult();
				if(null== createAlarmResult){
					alarmResult.fail(ErrorCodeConstants.SYSTEM_ERROR_CODE,ErrorCodeConstants.SYSTEM_ERROR_MSG);
					return alarmResult;
				}
				if(!AlarmConstants.ALARMA_SUCCESS.equals(createAlarmResult.getCode())){
					alarmResult.fail(createAlarmResult.getCode(),createAlarmResult.getMessage());
					return alarmResult;
				}else{
					Map<String,Object> map = new HashMap<String,Object>();
					map.put("sendStatus",AlarmSendStatus.SEND_YES);
					map.put("alarmsId",alarmInto.getAlarmsId());
					map.put("updateTime",new Date());
					alarmsInfoService.updateSendStatusByAlarmsId(map);
				}
			}
			return alarmResult;
		}catch (Exception e){
			LOGGER.error("调用第三方告警接口异常",e);
			alarmResult =new AlarmResult();
			alarmResult.setResponseMsg(ErrorCodeConstants.SYSTEM_ERROR_MSG);
			alarmResult.setResponseCode(ErrorCodeConstants.SYSTEM_ERROR_CODE);
			return alarmResult;
		}
	}
	
	
	public boolean updateAlarm(String alarmId, String alarmStatus,String productCode) {
		LOGGER.info("告警ID为:{},告警状态:{}", alarmId, alarmStatus);
		try {
			UpdateResponse updateResponse = new UpdateResponse();
			GetResponse getResponse = null;
			UpdateRequest request = null;
			
			if(AlarmConstants.TYPE_SKYWALKING.equalsIgnoreCase(productCode)){
				getResponse = getES(AlarmConstants.SKYWALKING_INDEX_NAME, AlarmConstants.SKYWALKING_TYPE_NAME, alarmId);
				request = getUpdateRequest(getResponse,AlarmConstants.SKYWALKING_INDEX_NAME, AlarmConstants.SKYWALKING_TYPE_NAME, alarmId);
			}else if(AlarmConstants.TYPE_PROMETHEUS.equalsIgnoreCase(productCode)){
        		getResponse = getES(AlarmConstants.PROMETHEUS_INDEX_NAME, AlarmConstants.PROMETHEUS_TYPE_NAME, alarmId);
        		request = getUpdateRequest(getResponse,AlarmConstants.PROMETHEUS_INDEX_NAME, AlarmConstants.PROMETHEUS_TYPE_NAME, alarmId);
			} else if(AlarmConstants.TYPE_ZABBIX.equalsIgnoreCase(productCode)){
				getResponse = getES(AlarmConstants.ZABBIX_INDEX_NAME, AlarmConstants.ZABBIX_TYPE_NAME, alarmId);
			    request = getUpdateRequest(getResponse,AlarmConstants.ZABBIX_INDEX_NAME, AlarmConstants.ZABBIX_TYPE_NAME, alarmId);
			}else{
				getResponse = getES(AlarmConstants.BUSINESS_INDEX_NAME, AlarmConstants.BUSINESS_TYPE_NAME, alarmId);
			    request = getUpdateRequest(getResponse,AlarmConstants.BUSINESS_INDEX_NAME, AlarmConstants.BUSINESS_TYPE_NAME, alarmId);
			}
			
			if(request==null){
				return true;
			}
			XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
			if (alarmStatus != null) {
				builder.field("alarmStatus", alarmStatus);
			}
			builder.endObject();
			request.doc(builder);
			updateResponse = client.update(request).get();
			LOGGER.info("更新ES结果:{}",updateResponse.getResult());
		} catch (Exception e) {
			LOGGER.error("更新告警数据失败:", e);
			return false;
		}
		return true;
	}
	
	//获取ES 告警数据
	private GetResponse getES( String alarmIndex,String alarmType,String alarmId){
		GetResponse getResponse = client.prepareGet(alarmIndex,alarmType, alarmId).execute().actionGet();
		return getResponse;
	}
	
	private UpdateRequest getUpdateRequest(GetResponse getResponse,String alarmIndex,String alarmType,String alarmId){
		UpdateRequest updateRequest = null;
		if(getResponse != null && getResponse.isExists()){
		   updateRequest = new UpdateRequest(alarmIndex, alarmType, alarmId); 
		}
		return updateRequest;
	}

	public CommonResult updateAlarmStatus(ResponseAlarmInfo responseAlarmInfo){
		CommonResult res = new CommonResult();
		try{
			rabbitTemplate.convertAndSend("cloudAlertFeedback.queue", responseAlarmInfo);
		} catch (Exception e) {
			res.fail("9999", "updateAlarmStatus生产消息到MQ异常");
			LOGGER.error("updateAlarmStatus生产消息到MQ异常,", e);
		}
		return res;
	}

}
